<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
</body>
<script>
  /**
   * 问题：
   * 什么是vue的依赖收集？
   * 
   * 答案：
   * vue的每个响应式属性都会产生一个dep,
   * 当副作用函数执行前，使用到了我们的响应式属性以后，此时就会进行依赖收集，这里收集的依赖就是当前正在执行的副作用函数
   * 而当我们修改属性以后，就会进入到set方法通过dep.notify进行通知，让我们收集的副作用函数进行执行
   * 
   * 问题：
   * 副作用函数去中为什么不能修改属性？
   * 
   * 答案：
   * 循环触发
   * 
  */


  // 响应式原理
  function oberserver (data) {
    const vm = {}
    const keys = Object.keys(data)

    for(let i = 0; i < keys.length; i++) {
      const key = keys[i]
      const dep = new Dep()
      let val = data[key]

      Object.defineProperty(vm, key, {
        get() {
          dep.depend()
          return val
        },
        set(newVal) {
          val = newVal
          dep.notify()
        },
      })
    }
    return vm
  }

  // 依赖跟踪
  class Dep {
    constructor() {
      this.subs = new Set()
    }
    depend() {
      if(activeUpdate) {
        this.subs.add(activeUpdate)
      }
    }
    notify() {
      this.subs.forEach(sub => sub())
    }
  }

  // 记录当前运行的副作用函数
  let activeUpdate
  // 副作用函数
  const effect = function(cb) {
    function wrappedUpdate() {
      activeUpdate = wrappedUpdate
      cb()
      activeUpdate = null
    }
    wrappedUpdate()
  }

  // 测试
  const data = oberserver({
    name: 1
  })
  effect(function() {
    document.getElementById('app').innerHTML = `${data.name}`
  })
  setInterval(()=> {
    data.name++
  }, 1000)
</script>
</html>
